//! \file backtacer_linux_arm.c

#include <stdio.h>
#include <unistd.h>

#include "backtracer.h"
#include "backtracer_linux_arm.h"

//------------------------------------------------------------------------------

TBGError GenBacktraceCurrent(func_map *pmap) {
    TBGError ret = 0;
    CHECK_DBG_ERR(pmap, NULL_PTR);
    void *cur_fp = NULL;
    void *cur_pc = NULL;
    asm volatile("mov %[cur_sp], fp\n\t"
                 "mov %[cur_pc], pc\n\t"
                 : [cur_sp] "=r" (cur_fp), [cur_pc] "=r" (cur_pc));

    CHECK_CALL(DefaultBacktrace(pmap, cur_fp, cur_pc), exit_point, ret);
exit_point:
    return ret;
}

//------------------------------------------------------------------------------

void _SigSegvHandler(int sig, siginfo_t *psiginfo, void *pcontext) {
    func_map *pmap = (func_map*) _SigHandlerGetSetFuncMap(NULL);
    CHECK_DBG_ERR(pmap, CANNOT_GET_STORED_ARG);

    //protection from SigSegv segmentation faults
    static int already_failed = false;
    CHECK_ERR(!already_failed, ALREADY_FAILED);
    already_failed = true;

    ucontext_t *pcont = (ucontext_t*) pcontext;
    CHECK(DefaultBacktraceExidx(pmap, (void*) pcont->uc_mcontext.arm_fp,
                                      (void*) pcont->uc_mcontext.arm_pc));
    _exit(0);
}

//------------------------------------------------------------------------------

func_map *_SigHandlerGetSetFuncMap(func_map *pmap) {
    static func_map *pmap_;
    if(pmap)
        pmap_ = pmap;
    CHECK_DBG_ERR(pmap_, CANNOT_GET_STORED_ARG);
    return pmap_;
}

